package com.moyu.plugin.cat

import com.moyu.plugin.Constants
import org.objectweb.asm.AnnotationVisitor
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.commons.AdviceAdapter

/**
 * 自定义ASM MethodVisitor实现类，用于在方法执行前后插入监控逻辑
 *
 * @param api            ASM API版本号
 * @param mv             下一个MethodVisitor实例（用于链式调用）
 * @param access         方法访问权限标志
 * @param className      当前处理的类名
 * @param methodName     当前处理的方法名
 * @param desc           方法描述符（参数及返回类型）
 */
internal class CatMethodVisitor(
    api: Int,
    mv: MethodVisitor?,
    access: Int,
    private val className: String?,
    private val methodName: String?,
    private val desc: String?
) : AdviceAdapter(api, mv, access, methodName, desc) {

    init {
        // 调试初始化信息，显示当前处理的方法信息
        println()
        println("visit method $className $methodName")
    }

    // 标记是否需要注入监控逻辑
    private var isInjected = false

    // 记录方法开始时间的局部变量位置
    private var startTimeId = 0

    // 记录方法唯一标识的局部变量位置
    private var methodId = 0

    // 判断方法是否为静态方法
    private val isStaticMethod: Boolean = access and Opcodes.ACC_STATIC != 0

    // 解析方法参数类型列表
    private val argumentArrays: Array<Type> = Type.getArgumentTypes(desc)


    /**
     * 处理方法注解，判断是否需要注入监控逻辑
     *
     * @param desc        注解描述符（全限定类名）
     * @param visible     是否可见（true为类可见，false为运行时可见）
     */
    override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor {
        // 当注解匹配且方法名为"test"时启用监控
        if (Constants.method_annotation == desc && methodName.equals("test")) {
            isInjected = true
            println("method_annotation:$desc")
        } else {
            isInjected = false
        }
        // 调试输出注解信息

        return super.visitAnnotation(desc, visible)
    }

    /**
     * 方法执行前的钩子，用于插入监控逻辑
     */
    override fun onMethodEnter() {
        if (isInjected) {
            println("============CatMethodVisitor init================")
            println("onMethodEnter:")

            // 当前未注释的监控逻辑（测试用Log.d）
            mv.visitLdcInsn("TAG")
            mv.visitLdcInsn("test: ")
            mv.visitMethodInsn(
                INVOKESTATIC,
                "android/util/Log",
                "d",
                "(Ljava/lang/String;Ljava/lang/String;)I",
                false
            );
            mv.visitInsn(POP)// 弹出Log.d返回的int值
        }
    }

    /**
     * 方法执行后的钩子，用于清理和结果记录
     */
    override fun onMethodExit(opcode: Int) {
        if (isInjected) {
            println("onMethodExit:")
            // 调试输出方法结束信息
            println("============CatMethodVisitor================")
            println()
        }

    }
}